package com.autotest.nore.service;

import org.apache.commons.io.IOUtils;
import java.nio.charset.StandardCharsets;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.autotest.nore.domain.Api;
import com.autotest.nore.domain.CaseApi;
import com.autotest.nore.dto.BodyContent;
import com.autotest.nore.mapper.ApiMapper;
import com.autotest.nore.mapper.CaseApiMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

@Slf4j
@Service
public class MockService {

    @Autowired
    private ApiMapper apiMapper;

    @Autowired
    private CaseApiMapper caseApiMapper;

    private final ObjectMapper objectMapper = new ObjectMapper();

    public ResponseEntity<Map<String, Object>> mockResponse(
            String modulePrefix,
            String path,
            RequestMethod method,
            HttpServletRequest request) {

        try {
            // 1. 匹配API路径和方法
            Api api = apiMapper.findByPathMethodAndModulePrefix(path, method.name(),modulePrefix);
            if (api == null) {
                return notFoundResponse("API not found for path: " + path);
            }

            // 2. 获取该API下的所有用例
            List<CaseApi> cases = caseApiMapper.findByApiId(api.getId());
            if (cases.isEmpty()) {
                return notFoundResponse("No test cases found for API: " + api.getId());
            }


            // 3. 根据请求内容匹配最合适的用例
            CaseApi matchedCase = findBestMatchingCase(cases,method,request);
            if (matchedCase == null) {
                return notFoundResponse("No matching test case found for request");
            }

            // 4. 返回mock_response
            return buildMockResponse(matchedCase);

        } catch (Exception e) {
            log.error("Mock request failed. Path: {}, Method: {}", path, method, e);
            return serverErrorResponse("Internal server error");
        }
    }

    private CaseApi findBestMatchingCase(List<CaseApi> cases,RequestMethod method, HttpServletRequest request) {
        // 请求内容类型
        String contentType = request.getContentType();
        // 请求参数
        Map<String, String> requestParams = extractRequestParams(request);
        boolean requestHasParams = !requestParams.isEmpty(); // 明确声明参数存在标志

        switch(method.toString().toUpperCase()){
            case "GET":
                // 2. 优先处理无参数请求的情况
                if (!requestHasParams) {
                    return findCaseWithEmptyQuery(cases); // 专门处理空参数匹配
                }
                // 3. 有参数请求的精确匹配
                for (CaseApi caseApi : cases) {
                    if (isExactMatch(caseApi.getQuery(), requestParams)) {
                        return caseApi;
                    }
                }
                break;
            case "POST":
                // 处理POST请求
                try {

                    String requestBody = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);

                    for (CaseApi caseApi : cases) {
                        String bodyJson = caseApi.getBody();
                        if (bodyJson == null || bodyJson.isEmpty()) {
                            continue;
                        }

                        BodyContent bodyContent = parseBodyContent(bodyJson);
                        if (bodyContent == null) {
                            continue;
                        }

                        boolean isMatch = false;
                        if (contentType == null || contentType.contains("none")) {
                            isMatch = bodyContent.getType().equals("none");
                        }else if (contentType.contains("x-www-form-urlencoded")) {
                            isMatch = matchFormUrlEncoded(bodyContent, requestBody);
                        } else if (contentType.contains("json")) {
                            isMatch = matchJson(bodyContent, requestBody);
                        } else if (contentType.contains("multipart/form-data")) {
                            isMatch = matchMultipartFormData(bodyContent, request);
                        } else if (contentType.contains("text/plain")) {
                            isMatch = matchTextPlain(bodyContent, requestBody);
                        }

                        if (isMatch) {
                            return caseApi;
                        }
                    }
                } catch (IOException e) {
                    log.error("Failed to read request body", e);
                }
                break;
            case "PUT":
                return matchBodyBasedRequest(cases, contentType, request, "PUT");
            case "DELETE":
                return matchBodyBasedRequest(cases, contentType, request, "DELETE");
            case "HEAD":
                // HEAD请求不包含body，直接返回第一个用例（HEAD通常用于检查资源是否存在）
                return cases.stream()
                        .findFirst()  // 直接取第一个
                        .orElse(null);
            case "PATCH":
                return matchBodyBasedRequest(cases, contentType, request, "PATCH");
            case "OPTIONS":
                // OPTIONS通常用于预检请求，返回固定响应
                return cases.isEmpty() ? null : cases.get(0);
        }

        return null; // 没有完全匹配的用例
    }

    /**
     * 专门匹配query为空的用例（无参数请求时使用）
     */
    private CaseApi findCaseWithEmptyQuery(List<CaseApi> cases) {
        return cases.stream()
                .filter(caseApi -> {
                    String query = caseApi.getQuery();
                    return query == null || query.isEmpty() || query.equals("[]");
                })
                .findFirst()
                .orElse(null);
    }
    /**
     * 精确参数匹配逻辑
     */
    private boolean isExactMatch(String queryJson, Map<String, String> requestParams) {
        if (queryJson == null || queryJson.isEmpty() || queryJson.equals("[]") || queryJson.equals("null")) {
            return false; // 用例无query条件，不匹配有参数的请求
        }

        try {
            JSONArray queryParams = JSON.parseArray(queryJson);
            for (int i = 0; i < queryParams.size(); i++) {
                JSONObject paramDef = queryParams.getJSONObject(i);
                String name = paramDef.getString("name");
                String value = paramDef.getString("value");

                if (!requestParams.containsKey(name) || !value.equals(requestParams.get(name))) {
                    return false;
                }
            }
            return true;
        } catch (JSONException e) {
            log.error("JSON解析失败: {}", queryJson, e);
            return false;
        }
    }



    private Map<String, String> extractRequestParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();

        try {
            if (request instanceof MultipartHttpServletRequest) {
                MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
                multipartRequest.getParameterMap().forEach((k, v) -> params.put(k, v[0]));
            } else {
                request.getParameterMap().forEach((k, v) -> params.put(k, v[0]));
            }
        } catch (Exception e) {
            log.warn("Failed to extract request parameters", e);
        }

        return params;
    }

    private BodyContent parseBodyContent(String bodyJson) {
        if (bodyJson == null || bodyJson.trim().isEmpty()) {
            return null;
        }

        try {
            // 第一次解析：将字符串转为 BodyContent 对象
            ObjectMapper objectMapper = new ObjectMapper();
            BodyContent bodyContent = objectMapper.readValue(bodyJson, BodyContent.class);

            return bodyContent;
        } catch (Exception e) {
            log.error("Failed to parse body content. Raw JSON:\n{}", bodyJson, e);
            return null;
        }
    }

    private ResponseEntity<Map<String, Object>> buildMockResponse(CaseApi matchedCase) {
        try {
            // 优先使用mock_response
            if (matchedCase.getMockResponse() != null) {
                return ResponseEntity.ok(objectMapper.readValue(matchedCase.getMockResponse(), Map.class));
            }

            // 没有mock_response则尝试从body构造
            BodyContent body = parseBodyContent(matchedCase.getBody());
            if (body != null) {
                if ("json".equals(body.getType()) && body.getJson() != null) {
                    return ResponseEntity.ok(objectMapper.readValue(body.getJson(), Map.class));
                } else if ("text".equals(body.getType()) && body.getRaw() != null) {
                    return ResponseEntity.ok(Map.of("response", body.getRaw()));
                }
            }

            // 默认响应
            return ResponseEntity.ok(Map.of(
                    "status", 0,
                    "message", "Success",
                    "caseId", matchedCase.getId()
            ));
        } catch (Exception e) {
            log.error("Failed to build mock response for case: {}", matchedCase.getId(), e);
            return serverErrorResponse("Failed to generate mock response");
        }
    }

    private ResponseEntity<Map<String, Object>> notFoundResponse(String message) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(Map.of("error", message));
    }

    private ResponseEntity<Map<String, Object>> serverErrorResponse(String message) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(Map.of("error", message));
    }
    /**
     * 匹配application/x-www-form-urlencoded类型请求
     */
    private boolean matchFormUrlEncoded(BodyContent bodyContent, String requestBody) {
        if (!"form-urlencoded".equals(bodyContent.getType())) {
            return false;
        }

        try {
            // 解析请求体
            Map<String, String> requestParams = parseFormUrlEncoded(requestBody);

            // 获取form列表并处理类型
            List<?> formList = (List<?>) bodyContent.getForm();
            if (formList == null) return false;

            for (Object item : formList) {
                if (!(item instanceof Map)) continue;

                Map<?, ?> formItem = (Map<?, ?>) item;
                String name = (String) formItem.get("name");
                String value = (String) formItem.get("value");

                if (name == null || value == null) continue;

                if (!requestParams.containsKey(name) || !value.equals(requestParams.get(name))) {

                        return false;

                }
            }
            return true;
        } catch (Exception e) {
            log.error("Form-urlencoded匹配失败", e);
            return false;
        }
    }
    /**
     * 匹配application/json类型请求
     */
    private boolean matchJson(BodyContent bodyContent, String requestBody) {
        if (!"json".equals(bodyContent.getType()) || bodyContent.getJson() == null) {
            return false;
        }

        try {
            JSONObject caseJson = JSON.parseObject(bodyContent.getJson());
            JSONObject requestJson = JSON.parseObject(requestBody);

            // 检查每个定义的字段是否匹配
            for (String key : caseJson.keySet()) {
                if (!requestJson.containsKey(key) ||
                        !caseJson.get(key).equals(requestJson.get(key))) {
                    return false;
                }
            }

            return true;
        } catch (JSONException e) {
            log.error("Failed to match JSON", e);
            return false;
        }
    }

    /**
     * 匹配multipart/form-data类型请求
     */
    /**
     * 匹配multipart/form-data类型请求
     */
    private boolean matchMultipartFormData(BodyContent bodyContent, HttpServletRequest request) {
        // 1. 检查类型是否为 form-data
        if (!"form-data".equals(bodyContent.getType())) {
            return false;
        }

        try {
            // 2. 获取请求参数（包括文件字段）
            Map<String, String[]> requestParams = request.getParameterMap();

            // 3. 检查 form 字段定义的参数是否完全匹配
            List<BodyContent.FormField> formFields = bodyContent.getForm();
            if (formFields == null || formFields.isEmpty()) {
                return false; // 用例未定义任何参数
            }

            // 4. 检查请求参数数量是否与定义一致（完全匹配要求）
            if (requestParams.size() != formFields.size()) {
                return false; // 参数数量不匹配
            }

            // 5. 逐个检查参数名和值
            for (BodyContent.FormField field : formFields) {
                String name = field.getName();
                String expectedValue = field.getValue();
                boolean required = field.isRequired();

                // 5.1 检查参数是否存在
                if (!requestParams.containsKey(name)) {
                    if (required) {
                        return false; // 缺少必需参数
                    }
                    continue; // 非必需参数允许缺失
                }

                // 5.2 检查参数值是否匹配
                String actualValue = requestParams.get(name)[0];
                if (!expectedValue.equals(actualValue)) {
                    return false; // 值不匹配
                }
            }

            // 6. 完全匹配通过
            return true;

        } catch (Exception e) {
            log.error("Multipart/form-data 匹配失败", e);
            return false;
        }
    }
    /**
     * 匹配text/plain类型请求
     */
    private boolean matchTextPlain(BodyContent bodyContent, String requestBody) {
        return "text".equals(bodyContent.getType()) &&
                requestBody.equals(bodyContent.getRaw());
    }

    /**
     * 解析application/x-www-form-urlencoded请求体
     */
    private Map<String, String> parseFormUrlEncoded(String formData) {
        return Arrays.stream(formData.split("&"))
                .map(pair -> pair.split("="))
                .collect(Collectors.toMap(
                        arr -> URLDecoder.decode(arr[0], StandardCharsets.UTF_8),
                        arr -> URLDecoder.decode(arr.length > 1 ? arr[1] : "", StandardCharsets.UTF_8)
                ));
    }

    /**
     * 通用带Body请求的匹配逻辑（用于PUT/DELETE/PATCH）
     */
    private CaseApi matchBodyBasedRequest(List<CaseApi> cases, String contentType,
                                          HttpServletRequest request, String method) {
        try {
            String requestBody = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);

            for (CaseApi caseApi : cases) {

                String bodyJson = caseApi.getBody();
                if (bodyJson == null || bodyJson.isEmpty()) {
                    continue;
                }

                BodyContent bodyContent = parseBodyContent(bodyJson);
                if (bodyContent == null) {
                    continue;
                }

                boolean isMatch = false;
                if (contentType == null || contentType.contains("none")) {
                    isMatch = bodyContent.getType().equals("none");
                } else if (contentType.contains("x-www-form-urlencoded")) {
                    isMatch = matchFormUrlEncoded(bodyContent, requestBody);
                } else if (contentType.contains("json")) {
                    isMatch = matchJson(bodyContent, requestBody);
                } else if (contentType.contains("multipart/form-data")) {
                    isMatch = matchMultipartFormData(bodyContent, request);
                } else if (contentType.contains("text/plain")) {
                    isMatch = matchTextPlain(bodyContent, requestBody);
                }

                if (isMatch) {
                    return caseApi;
                }
            }
        } catch (IOException e) {
            log.error("Failed to read {} request body", method, e);
        }
        return null;
    }


}